Prijeđi na sadržaj

Switch naredba

Izvor: Wikipedija

U računalnom programiranju, switch naredba je tip upravljačke naredbe koja postoji u većini suvremenih imperativnih programskih jezika (npr. C, C++, C# i Java). Svrha joj je da dopusti vrijednosti varijable ili izraza upravljanje tokom izvršavanja programa. U nekim drugim programskim jezicima je naredba sintaksno različita ali koncepcijski ista kao switch naredba poznata kao case naredba ili select naredba.

U većini se jezika switch naredba definira preko više pojedinih naredbi. Tipična je sintaksa takva da prva linija koda sadrži ključnu riječ "switch" nakon koje slijedi ili ime varijable ili neki drugi izraz kojeg dopušta sintaksa jezika. Ova se varijabla ili izraz obično zove "upravljačka varijabla" switch naredbe. Nakon ove linije koda slijede linije koda koje definiraju jedan ili više blokova koda koji predstavljaju moguća grananja programa.

Svaki blok počinje linijom koja sadrži ključnu riječ case nakon koje slijedi vrijednost koju upravljačka varijabla može sadržavati. Ako vrijednost upravljačke naredbe sparuje ovu vrijednost, izvršavanje će programa skočiti na taj blok koda. Ako ne, ispituje se vrijednost specificirana u sljedećem bloku (ako je prisutan) i proces se ponavlja.

Dopušten je i opcionalni posebni blok koji ne specificira nijednu vrijednost i koji počinje ključnom riječju default mjesto ključnom riječju case. Ako je ovaj blok prisutan i ako nijedna od vrijednosti izlistanih za druge blokove ne sparuje vrijednost upravljačke varijable, izvršavanje će programa skočiti na naredbu koja slijedi nakon ključne riječi default.

Valja spomenuti i metode terminiranja bloka. Tipično se koristi ključna riječ break za označavanje kraja bloka. Kad se do nje dođe, uzrokuje nastavljanje izvršavanja programa u naredbi koja slijedi nakon niza naredbi unutar switch naredbe, i tako kompletira izvršavanje switch naredbe. Ako ključna riječ break nije prisutna na kraju bloka, u mnogim će jezicima izvršavanje programa "propadati" u kod asociran sa sljedećim blokom switch naredbe, kao da je njegova vrijednost sparila vrijednost upravljačke varijable. Istaknute iznimke uključuju C#, u kojem propadanje nije dopušteno osim ako je blok prazan i svi blokovi moraju biti terminirani break naredbom ili rabeći neku drugu ključnu riječ. Slično, gotovo svi BASIC dijalekti koji posjeduju ovu naredbu ne dopuštaju propadanje.

Primjeri

[uredi | uredi kôd]

Slijede jednostavni primjeri, napisani u različitim jezicima, koji rabe switch naredbu za ispis jedne od nekoliko mogućnosti, ovisno o vrijednosti cijelog broja unešenog od strane korisnika. Iscrpno se iskorištava nedostatak ključnih riječi break za propadanje iz jednog bloka u drugi izvođenjem programa. Primjerice, ako je n=5, druga case naredba će dati sparivanje upravljačke varijable. S obzirom na to da ne postoje ni naredbe nakon te linije koda kao niti ključne riječi break, izvršavanje nastavlja preko linije koda 'case 7:' sve do sljedeće, koja daje izlaz. Linija s ključnom riječju break nakon nje uzrokuje završenje switch naredbe. Ako korisnik unese više od jedne znamenke, izvršuje se default blok, dajući poruku o grješci.

 switch(n) {
     case 0:
       printf("Unijeli ste nulu.\n");
       break;
     case 3:
     case 5:
     case 7:
       printf("n je prost broj\n");
       break;
     case 2: printf("n je prost broj\n");
     case 4:
     case 6:
     case 8:
       printf("n je paran broj\n");
       break;
     case 1:
     case 9:
       printf("n je savršen kvadrat\n");
       break;
     default:
       printf("Dopušteni su samo jednoznamenkasti brojevi\n");
     break;
 }
 switch (n) {
    case 0:  System.out.println("Unijeli ste nulu.\n"); 
             break;
    case 3:  
    case 5:  
    case 7:  System.out.println("n je prost broj\n"); 
             break;
    case 2:  System.out.println("n je prost broj\n"); 
    case 4:  
    case 6:  
    case 8:  System.out.println("n je paran broj\n"); 
             break;
    case 1:  
    case 9:  System.out.println("n je savršen kvadrat\n"); 
             break;
    default: System.out.println("Dopušteni su samo jednoznamenkasti brojevi\n"); 
             break;
 }
 switch (varijabla) {
    case 0:  
             trace("slučaj za broj 0"); 
             break;
    case 1:  
             trace("slučaj za broj 1"); 
             break;
    case 2:  
             trace("slučaj za broj 2"); 
             break;

    /**
     * ''case'' naredbe u Actionscriptu ne moraju nužno koristiti brojeve,
     * i mogu se sparivati stringovi ili drugi tipovi.
     */

    case "A":
             trace("spareno je 'A'");
             break;
    
    /**
     * višestruki se slučajevi mogu grupirati
     */
    
    case "B","b":
             trace("spareno je 'B' ili 'b'");
             break;
   /**
    * Ovakvo grupiranje nije valjano, barem ne u Flashu 8
    * trebalo bi biti:
    */
    
   case "B":
   case "b":
             trace("spareno je 'B' ili 'b'");
             break;
    
    default: trace("nijedan ispitani slučaj nije sparen");
             break; 
 }
 
    /**    
     * Općenito, nešto je učinkovitije popuniti niz odgovora i pobrojavati kroz niz usporedbi u [[for petlja|for petlji]],
     * rabiti matematičku formulu u [[while petlja|while petlji]] itd., ali ''switch'' naredba može biti korisna za
     * dijagnostiku i lakša je za čitati usporedo s kodom, napose u slučaju kad je sadržaj [[niz]]a za usporedbu
     * popunjen izvana.
     */

REALbasic koristi nešto drukčiju sintaksu za isti koncept. Koristi naširoko korištenu BASIC sintaksu select case naredbe (Dartmouth BASIC je imao ovakvu naredbu još u srednjim 1970-im), te je stoga:

 select case nekiCijeliBroj
 case 0  // Jednostavan slučaj jedne naredbe
    RadiNešto
 
 case 1,2,5  // Rabeći višestruke vrijednosti
    RadiNeštoDrugo
 
 case 8 to 10  // Rabeći opseg vrijednosti
    RadiNeštoTreće
 
 case Is > 20  // Rabeći bulovski izraz
    JošJednom
 
 else  // pretpostavljen blok koda
    VišeNijednom
  
 end select

Ruby nema mehanizam "propadanja", također koristi case mjesto switch, when mjesto case i else mjesto default.

 case n
 when 0:       puts 'Unijeli ste nulu'
 when 1, 9:    puts 'n je savršen kvadrat'
 when 2:
   puts 'n je prost broj'
   puts 'n je paran broj'
 when 3, 5, 7: puts 'n je prost broj'
 when 4, 6, 8: puts 'n je paran broj'
 else          puts 'Dopušteni su samo jednoznamenkasti brojevi'
 end

C# koristi standardnu C-nalik sintaksu s dodatkom 'goto case' naredbe. Stringovi se također mogu rabiti u switch naredbama. Usto, "propadanje" je zabranjeno zahtijevanjem naredbe skoka za svaki slučaj (poput break ili goto) za vrijeme prevođenja.

 switch (nekiCijeliBroj)
 {
  case 0:
   goto case 1;
  case 1:
   return 1; // Vraća ako je nekiCijeliBroj 0 ili 1.
  case 2:
   nekiCijeliBroj++;
   goto case 3;
  case 3:
   RadiNešto();
   break;
  default:
   RadiNeštoDrugo();
   break;
 }

Simboličke konstante u switch naredbi

[uredi | uredi kôd]

U mnogim (ne i pod svim) okolnostima poraba imena mjesto običnih cijelih brojeva čini izvorni kod čitljivijim. Ovo nema utjecaja na ponašanje programa. Ovaj stil switch naredbe je uobičajen za implementaciju konačnih automata. Tradicija je u C-u takva da su konstante napisane velikim slovima, iako kompilator ne prisiljava takvo imenovanje. Slijedi nekoliko primjera:

C (rabeći pretprocesor)

[uredi | uredi kôd]
 #define STANJE_SPREMNO      1
 #define STANJE_POSTAVLJENO  2
 #define STANJE_IDI          3
 #define STANJE_NEUSPJEH     4
 
 switch( stanje )
 {
    case STANJE_SPREMNO:
        stanje = STANJE_POSTAVLJENO;
        if( x < 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_POSTAVLJENO:
        stanje = STANJE_IDI;
        if( y > 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_IDI:
        printf( "idi!\n" );
        break;
 
    case STANJE_NEUSPJEH:
        exit( -1 );
 }

C (rabeći enumeraciju)

[uredi | uredi kôd]
 enum
 {
    STANJE_SPREMNO = 1,
    STANJE_POSTAVLJENO = 2,
    STANJE_IDI = 3,
    STANJE_NEUSPJEH = 4,
 };
 
 switch( stanje )
 {
    case STANJE_SPREMNO:
        stanje = STANJE_POSTAVLJENO;
        if( x < 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_POSTAVLJENO:
        stanje = STANJE_IDI;
        if( y > 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_IDI:
        printf( "idi!\n" );
        break;
 
    case STANJE_NEUSPJEH:
        exit( -1 );
 }

C (const int nije dopušten u switch naredbi)

[uredi | uredi kôd]

UPOZORENJE: ovaj se primjer neće kompilirati standardnim C kompilatorom. Ključna riječ const u C-u je primjer slabe konstante i nije prikladna za uporabu kao jedan od slučajeva u switch naredbi.

 const int STANJE_SPREMNO = 1;
 const int STANJE_POSTAVLJENO = 2;
 const int STANJE_IDI = 3;
 const int STANJE_NEUSPJEH = 4;
 
 switch( stanje )
 {
    case STANJE_SPREMNO:
        stanje = STANJE_POSTAVLJENO;
        if( x < 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_POSTAVLJENO:
        stanje = STANJE_IDI;
        if( y > 0 ) stanje = STANJE_NEUSPJEH;
        break;
 
    case STANJE_IDI:
        printf( "idi!\n" );
        break;
 
    case STANJE_NEUSPJEH:
        exit( -1 );
 }

Alternativne uporabe

[uredi | uredi kôd]

Mnogi jezici također dopuštaju uporabu bulovske vrijednost "true" kao varijable i izraze kao pojedine slučajeve.

Primjerice, u PHP-u se može:

switch(true) {
  case ($x == 'bokić'): 
    foo(); 
    break;
  case ($z == 'kako si'): break;
}

Razlog zašto ovo uopće radi jest taj da varijabla koja se ispituje jest bulovska vrijednost. Stoga će x=='hello' kao uvjet vratiti ili istinu ili laž, pa ako je istinit, sparuje vrijednost koja se ispituje.

Ovo se također može rabiti za provjeru višestrukih varijabli za jednom vrijednosti mjesto provjere višestrukih vrijednosti za jednom varijablom:

//primjer 1: uobičajena uporaba
switch($x) {
  case 5: break;
  case 6: break;
}
//primjer 2: alternativna uporaba
switch(5) {
  case $x: break;
  case $y: break;
}

U Rubyju, zbog načina na koji on rukuje === jednakošću, naredba se case također može rabiti za ispitivanje klase varijable:

 case ulaz
 when Array: puts 'ulaz je Array!'
 when Hash:  puts 'ulaz je Hash!'
 end

Ruby također vraća vrijednost koja može biti dodijeljena varijabli i ustvari ni ne zahtijeva parametre za case (što je čini pomalo nalik else if naredbi):

 catfood = case
           when mačka.starost <= 1: mlado
           when mačka.starost > 10: staro
           else                     normalno
           end

Kompilacija

[uredi | uredi kôd]

Ako konstante oblikuju kompaktan opseg, switch naredba može biti ostvarena vrlo učinkovito kao da se radi o izboru zasnovanom na cijelim brojevima. Ovo se često ostvaruje tablicom skokova.

Prednosti i nedostatci

[uredi | uredi kôd]

U nekim se jezicima i programskim okolinama case ili switch naredba smatra čitljivijom i lakšom za održavati od istovjetnog niza if-else naredbi, s obzirom na to da je konciznija. Međutim, ako je ostvarena propadanjem, switch naredbe su čest izvor pogrešaka među programerima početnicima.

Alternative

[uredi | uredi kôd]

Jedna je alternativa switch naredbi uporaba tablice pretraživanja koja sadrži kao ključeve vrijednosti od case i kao vrijednosti dijelove pod case naredbom. U nekim su jezicima dopušteni samo stvarni podatkovni tipovi kao vrijednosti u tablici pretraživanja. U drugim je jezicima također moguće dodijeliti funkcije kao vrijednosti tablice pretraživanja, što daje istu fleksibilnost kao i stvarna switch naredba (ovo je jedan od načina implementacije switch naredbi u jeziku Lua koji nema ugrađeni switch[1]).

U nekim su slučajevima tablice pretraživanja učinkovitije od switch naredbi s obzirom na to da mnogi jezici mogu optimizirati pretragu tablice dok switch naredbe nisu tako često optimizirane.

Drugu "alternativu" switch naredbama predstavlja iscrpna uporaba polimorfizma.

Izvori

[uredi | uredi kôd]

Vidjeti također

[uredi | uredi kôd]